﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PLC
{
    public class SerialPortManager
    {
         static SerialPort serialPort=null;
        // SerialPort serialPort=null;
        // SerialPortManager serialPortManager = null;

        static String  _port  = "COM6";
        static int     _baudRate = 9600;
        static Parity  _parity = Parity.None;
        static StopBits _stopBits = StopBits.One;
        static int _dataBits = 8;
        // static Handshake handshake = Handshake.None;

        //初始化信号量，剩余资源为0，总资源个数为1


        static Boolean isOpen =false;

        public string retValue;

        public static SerialPortManager GetInstance(String port, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        {
            _port = port;
            _baudRate = baudRate;
            _parity = parity;
            _dataBits = dataBits;
            _stopBits = stopBits;
            if (serialPort == null)
            {
                serialPort = new SerialPort(_port, _baudRate, _parity, _dataBits, _stopBits);
            }

            SerialPortManager  serialPortManager= new SerialPortManager();


            return serialPortManager;
        }

        public Boolean IsOpen { get => isOpen; }


        public int Open()
        {
  

            //port.DataReceived += DataReceived;
           
            if (!isOpen)
            {
                serialPort.ReceivedBytesThreshold = 1;


                serialPort.DtrEnable = true;//获取或设置一个值，该值在串行通信过程中启用数据终端就绪 (DTR) 信号。
                serialPort.RtsEnable = true;//获取或设置一个值，该值指示在串行通信中是否启用请求发送 (RTS) 信号
                                            //设置数据读取超时为1秒
                serialPort.ReadTimeout = 1000;
                serialPort.Open();
                isOpen = true;
               
            }
            return 0;

        }

        public void Close()
        {
            if (isOpen)
            {
                //serialPort.DataReceived -= port_DataReceived;
                serialPort.Close();
                isOpen = false;
            }
        }


        #region 信号量版本
        /*
        Semaphore sema = new Semaphore(0, 1);
        volatile List<byte> portContent = new List<byte>();
        public byte[] readData()
        {
            //Console.WriteLine("begin read!!!");
            if (serialPort.IsOpen)
            {
                serialPort.Write(new byte[] { 0x55,0x1,0x34,0x8A}, 0, 4);

                bool ret = sema.WaitOne(1000);
                if (!ret)
                {
                    sema.Release();
                }
                else
                {
                    if (portContent.Count != 0)
                    {
                        byte[] receivedData = new byte[portContent.Count];
                        portContent.CopyTo(receivedData);
                        portContent.Clear();
                        return receivedData;
                    }
                    

                }

                return null;
            }
            return null;

        }

        

        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            
                try
                {
                    int buffer = serialPort.BytesToRead;
                    byte[] receivedData = new byte[buffer]; 
                    serialPort.Read(receivedData, 0, receivedData.Length);

                    StringBuilder sb = new StringBuilder();
                    //sb.Append("recieved (" + buffer + "):bytes, type:"+e.EventType+")");
                    for (int i = 0; i < receivedData.Length; i++)
                    {
                        portContent.Add(receivedData[i]);
                        //sb.Append(receivedData[i].ToString() + " ");
                    }
                    if (portContent.Count >= 24)
                    {
                        sema.Release();
                    }
                }
                catch (System.Exception ex)
                {
                    portContent.Clear();
                    sema.Release();
                }
        }
        */
        #endregion

        #region 等待版本

        
        Semaphore sema = new Semaphore(0, 1);



        /// <summary>
        /// 根据网上的说法，DataReceived回调的时候，缓冲区的数据可能没有被准备好，需要在回调函数port_DataReceived中等待一下
        /// </summary>
        /// <returns></returns>
        public byte[] readData()
        {
            byte[] portDataArr = new byte[72];
            //Console.WriteLine("begin read!!!");
            if (serialPort.IsOpen)
            {
                serialPort.Write(new byte[] { 0x55, 0x1, 0x34, 0x8A }, 0, 4);

                //采用信号量锁住了，确保只有一个任务接收
                bool ret = sema.WaitOne(1000);
                int counter = 0;
                int buffer = serialPort.BytesToRead;
                while ( buffer < 72 && counter ++ < 50)
                {
                    
                    Thread.Sleep(20);
                    buffer = serialPort.BytesToRead;
                }
                

                if (counter >= 50 || buffer < 72 )
                {
                    sema.Release();
                    return null;
                }

                serialPort.Read(portDataArr, 0, 72);

                return portDataArr;
            }

            return null;
        }



       

        #endregion

    }

}

